home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr46 / vfwdk.zip / VFWSDK.ZIP / SAMPLES / BRAVADO / CAP.C < prev    next >
C/C++ Source or Header  |  1993-01-31  |  14KB  |  505 lines

  1. /****************************************************************************
  2.  *
  3.  *   cap.c
  4.  * 
  5.  *   Main video capture module. Main capture ISR.
  6.  *
  7.  *   Microsoft Video for Windows Sample Capture Driver
  8.  *   Chips & Technologies 9001 based frame grabbers.
  9.  *
  10.  *   Copyright (c) 1992-1993 Microsoft Corporation.  All Rights Reserved.
  11.  *
  12.  *    You have a royalty-free right to use, modify, reproduce and 
  13.  *    distribute the Sample Files (and/or any modified version) in 
  14.  *    any way you find useful, provided that you agree that 
  15.  *    Microsoft has no warranty obligations or liability for any 
  16.  *    Sample Application Files which are modified. 
  17.  *
  18.  ***************************************************************************/
  19.         
  20. #include <windows.h>
  21. #include <mmsystem.h>
  22. #include <msvideo.h>
  23. #include <msviddrv.h>
  24. #include <stdlib.h>
  25. #include "ct.h"
  26. #include "debug.h"
  27.  
  28. #ifndef DriverCallback
  29. BOOL WINAPI DriverCallback(DWORD dwCallback, UINT uFlags,
  30.     HANDLE hDevice, UINT uMessage, DWORD dwUser, DWORD dwParam1, DWORD dwParam2);
  31. #endif
  32.  
  33. // The following are constants which define, in microseconds,
  34. // the time between vertical retrace interrupts
  35. // for either frames or fields.
  36.  
  37. #if FRAME_INTERRUPT
  38. #define NTSCMICROSECPERTICK       33367L // = 1/59.94   = 33 mS per Frame
  39. #define  PALMICROSECPERTICK       40000L // = 1/50.00   = 40 mS per Frame
  40. #else
  41. #define NTSCMICROSECPERTICK       16683L // 1/(2*59.94) = 16 mS per Field
  42. #define  PALMICROSECPERTICK       20000L // 1/(2*50.00) = 20 mS per Field
  43. #endif
  44.  
  45. //
  46. //  we use the reserved fields of a VIDEOHDR for linked list pointers
  47. //
  48. #define NEXT(p)     (LPVIDEOHDR)(p->dwReserved[0])
  49.  
  50. /* Local to this module */
  51. LPVIDEOHDR    lpVHdrFirst;
  52. LPVIDEOHDR      lpVHdrLast;
  53. BOOL        fVideoOpen = FALSE;
  54. DWORD        dwTimeStart;
  55. DWORD        dwTimeStream;
  56. DWORD        dwMicroSecPerFrame;
  57. DWORD        dwMicroSecPerTick; // Accounts for 59.95 video frames per sec.
  58. DWORD        dwNextFrameNum;
  59. DWORD        dwLastVideoClock;
  60. DWORD           dwFramesSkipped = 0;
  61. VIDEO_STREAM_INIT_PARMS  CaptureStreamParms;
  62.  
  63. /* 
  64.  * Return the number of frames skipped to date.  This count will be
  65.  *      inaccurate if the frame rate requested is over 15fps.
  66.  * This function implements the DVM_STREAM_GETERROR message.
  67.  */
  68. DWORD FAR PASCAL InStreamError(LPDWORD lpdwErrorType, LPDWORD lpdwFramesSkipped)
  69. {
  70.     if (lpdwErrorType)
  71.         *lpdwErrorType = (dwFramesSkipped ? DV_ERR_NO_BUFFERS : DV_ERR_OK);
  72.     if (lpdwFramesSkipped)
  73.         *lpdwFramesSkipped = dwFramesSkipped;
  74.     dwFramesSkipped = 0;
  75.     return( DV_ERR_OK );
  76. }
  77.  
  78. /* 
  79.  * Return the current stream time from the start of capture based
  80.  *      on the number of vsync interrupts.
  81.  * This function implements the DVM_STREAM_GETPOSITION message.
  82.  */
  83. DWORD FAR PASCAL InStreamGetPos( LPMMTIME lpMMTime, DWORD dwSize)
  84. {
  85.     if (dwSize != sizeof (MMTIME)) 
  86.         return DV_ERR_NOTSUPPORTED;
  87.     lpMMTime->wType = TIME_MS;
  88.     lpMMTime->u.ms = dwTimeStream;
  89.     return( DV_ERR_OK );
  90. }
  91.  
  92.  
  93. /****************************************************************************
  94.  *  videoCallback()  This calls DriverCallback for the input stream
  95.  *
  96.  *  msg         The message to send.
  97.  *
  98.  *  dw1        Message-dependent parameter.
  99.  *
  100.  * There is no return value.
  101.  ***************************************************************************/
  102.  
  103. void FAR PASCAL videoCallback(WORD msg, DWORD dw1)
  104. {
  105.     // invoke the callback function, if it exists.  dwFlags contains driver-
  106.     // specific flags in the LOWORD and generic driver flags in the HIWORD
  107.  
  108.     if (CaptureStreamParms.dwCallback)
  109.         DriverCallback (CaptureStreamParms.dwCallback,    // client's callback DWORD
  110.                  HIWORD(CaptureStreamParms.dwFlags),  // callback flags
  111.                  (HANDLE) CaptureStreamParms.hVideo,         // handle to the device
  112.                  msg,                     // the message
  113.                  CaptureStreamParms.dwCallbackInst,  // client's instance data
  114.                  dw1,                     // first DWORD
  115.                  0);                      // second DWORD not used
  116. }
  117.  
  118.  
  119. /* 
  120.  * Capture a frame
  121.  * This function implements the DVM_FRAME message.
  122.  */
  123. WORD FAR PASCAL CaptureFrame(LPVIDEOHDR lpVHdr)
  124. {
  125.     int j;
  126.     unsigned char huge *hpc;
  127.     
  128. #ifdef USE_PROFILER
  129.     ProfStart ();
  130. #endif
  131.  
  132.     if (lpVHdr->dwBufferLength < biDest.biSizeImage)
  133.         return DV_ERR_SIZEFIELD; //!!!???
  134.  
  135.     CT_GrabFrame ();            // Get a new frame
  136.     
  137.     /* either grab a 8, 16, or 24 bit DIB, or YUV */
  138.     switch( gwDestFormat )
  139.     {
  140.         case IMAGE_FORMAT_PAL8:
  141.             RectCopyBytes(fpCopyBuffer, gwWidth * 2, 
  142.                 glpFrameBuffer, gwWidthBytes,
  143.                 0, 0, gwWidth * 2, gwHeight);
  144.             CT_Acquire (TRUE);
  145.             mapUnpackedYUVto8(lpVHdr->lpData,fpCopyBuffer,fpTrans16to8,
  146.                    gwWidth, gwHeight, gwWidth*2);
  147.             break;
  148.  
  149.         case IMAGE_FORMAT_RGB16:
  150.             RectCopyBytes(fpCopyBuffer, gwWidth * 2, 
  151.                 glpFrameBuffer, gwWidthBytes,
  152.                 0, 0, gwWidth * 2, gwHeight);
  153.             CT_Acquire (TRUE);
  154.             mapUnpackedYUVtoRGB16(lpVHdr->lpData,fpCopyBuffer,fpYUVtoRGB16,
  155.                    gwWidth, gwHeight, gwWidth*2);
  156.             break;
  157.  
  158.         case IMAGE_FORMAT_RGB24:
  159.             RectCopyBytes(fpCopyBuffer, gwWidth * 2, 
  160.                 glpFrameBuffer, gwWidthBytes,
  161.                 0, 0, gwWidth * 2, gwHeight);
  162.             CT_Acquire (TRUE);
  163.             for (j = 0; j < (int) gwHeight; j++) {
  164.                 hpc = (unsigned char huge *) fpCopyBuffer + 
  165.                         ((LONG) gwWidth * 2 * j);
  166.                 CT_YUV2RGBNoInterp (hpc, (BYTE huge *) lpVHdr->lpData + 
  167.                         ((LONG) gwWidthBytesDest * (gwHeight - (j + 1))), 
  168.                         gwWidth, 24);
  169.             }
  170.             break;
  171.  
  172.         case IMAGE_FORMAT_YUV411UNPACKED:
  173.            RectCopyBytes(lpVHdr->lpData, gwWidth * 2, 
  174.                glpFrameBuffer, gwWidthBytes,
  175.                0, 0, gwWidth * 2, gwHeight);
  176.            CT_Acquire (TRUE);
  177.            break;
  178.  
  179.         default:
  180.             return DV_ERR_BADFORMAT;
  181.     }
  182.  
  183.     lpVHdr->dwBytesUsed = biDest.biSizeImage;
  184.     lpVHdr->dwTimeCaptured = timeGetTime ();
  185.     lpVHdr->dwFlags |= VHDR_KEYFRAME;
  186.  
  187. #ifdef USE_PROFILER
  188.     ProfStop ();
  189. #endif
  190.     
  191.     return DV_ERR_OK;
  192. }
  193.  
  194. /*
  195.  *
  196.  * Initalize video driver for input.  
  197.  * This function implements the DVM_STREAM_INIT message.
  198.  *
  199.  */
  200. WORD FAR PASCAL InStreamOpen( LPVIDEO_STREAM_INIT_PARMS lpStreamInitParms )
  201. {
  202.     if (fVideoOpen)
  203.         return DV_ERR_NONSPECIFIC;
  204.  
  205.     CaptureStreamParms = *lpStreamInitParms;
  206.  
  207.     /* Page lock the data since it will be used at interrupt time */
  208.     GlobalPageLock(HIWORD(fpTrans16to8));
  209.     GlobalPageLock(HIWORD(fpCopyBuffer));
  210.  
  211.     if (gwDestFormat == IMAGE_FORMAT_RGB16) 
  212.         GlobalPageLock(HIWORD(fpYUVtoRGB16));
  213.  
  214.     fVideoOpen = TRUE;
  215.     
  216.     dwNextFrameNum = 0L;
  217.     dwTimeStream = 0L;
  218.     dwFramesSkipped = 0L;
  219.  
  220.     lpVHdrFirst = NULL;
  221.     lpVHdrLast = NULL;
  222.  
  223.     CT_Acquire (TRUE);
  224.     
  225.     dwMicroSecPerFrame = lpStreamInitParms-> dwMicroSecPerFrame;
  226.  
  227.     dwMicroSecPerTick = gfEurope ? PALMICROSECPERTICK :
  228.                                   NTSCMICROSECPERTICK;
  229.  
  230.     videoCallback(MM_DRVM_OPEN, 0L); // Notify app we're open via callback
  231.  
  232.     IRQEnable ();
  233.  
  234.     return DV_ERR_OK;
  235. }
  236.  
  237. /*
  238.  *
  239.  * Fini video driver input
  240.  * This function implements the DVM_STREAM_FINI message.
  241.  *
  242.  */
  243. WORD FAR PASCAL InStreamClose( void )
  244. {
  245.     if( !fVideoOpen )
  246.         return DV_ERR_NONSPECIFIC;
  247.  
  248.     if (lpVHdrFirst)
  249.         return DV_ERR_STILLPLAYING;
  250.  
  251.     InStreamStop();
  252.  
  253.     fVideoOpen = FALSE;
  254.     
  255.     GlobalPageUnlock (HIWORD (fpCopyBuffer));
  256.     GlobalPageUnlock (HIWORD (fpTrans16to8));
  257.     if (gwDestFormat == IMAGE_FORMAT_RGB16) 
  258.         GlobalPageUnlock(HIWORD(fpYUVtoRGB16));
  259.  
  260.     lpVHdrFirst = NULL;
  261.     lpVHdrLast = NULL; 
  262.  
  263.     IRQDisable ();
  264.     videoCallback(MM_DRVM_CLOSE, 0L); // Notify app we're closed via callback
  265.  
  266.     return DV_ERR_OK;
  267. }
  268.  
  269.  
  270. LPVIDEOHDR  NEAR PASCAL DeQueHeader()
  271. {
  272.     LPVIDEOHDR lpVHdr;
  273.  
  274.     if (lpVHdr = lpVHdrFirst) {
  275.         lpVHdr->dwFlags &= ~VHDR_INQUEUE;
  276.  
  277.         _asm cli
  278.  
  279.         lpVHdrFirst = NEXT(lpVHdr);
  280.  
  281.         if (lpVHdrFirst == NULL)
  282.             lpVHdrLast = NULL;
  283.  
  284.         _asm sti
  285.     }
  286.  
  287.     return lpVHdr;
  288. }
  289.  
  290. void NEAR PASCAL QueHeader(LPVIDEOHDR lpVHdr)
  291. {
  292.     lpVHdr->dwFlags &= ~VHDR_DONE;
  293.     lpVHdr->dwFlags |= VHDR_INQUEUE;
  294.  
  295.     NEXT(lpVHdr) = NULL;
  296.  
  297.     _asm cli
  298.  
  299.     if (lpVHdrLast)
  300.         NEXT(lpVHdrLast) = lpVHdr;
  301.     else
  302.         lpVHdrFirst = lpVHdr;
  303.  
  304.     lpVHdrLast = lpVHdr;
  305.  
  306.     _asm sti
  307. }
  308.  
  309. /*
  310.  *
  311.  * Add a buffer to the input queue
  312.  * This function implements the DVM_STREAM_ADDBUFFER message.
  313.  *
  314.  */
  315. WORD FAR PASCAL InStreamAddBuffer( LPVIDEOHDR lpVHdr )
  316. {
  317.     if( !fVideoOpen )
  318.         return DV_ERR_NONSPECIFIC;
  319.  
  320.     /* return error if no node passed */
  321.     if (!lpVHdr)
  322.         return DV_ERR_NONSPECIFIC;
  323.  
  324.     /* return error if buffer has not been prepared */
  325.     if (!(lpVHdr->dwFlags & VHDR_PREPARED))
  326.         return DV_ERR_UNPREPARED;
  327.  
  328.     /* return error if buffer is already in the queue */
  329.     if (lpVHdr->dwFlags & VHDR_INQUEUE)
  330.         return DV_ERR_NONSPECIFIC;
  331.  
  332.     if (lpVHdr->dwBufferLength < biDest.biSizeImage)
  333.         return DV_ERR_NONSPECIFIC;
  334.  
  335.     /* set back to basic flag */
  336.     lpVHdr->dwFlags &= ~VHDR_DONE;
  337.     lpVHdr->dwBytesUsed = 0;
  338.  
  339.     QueHeader(lpVHdr);
  340.  
  341.     return DV_ERR_OK;
  342. }
  343.  
  344. /*
  345.  *
  346.  * Start the recording - all buffers should be prepared
  347.  * This function implements the DVM_STREAM_START message.
  348.  *
  349.  */
  350. WORD FAR PASCAL InStreamStart( void )
  351. {
  352.     if( !fVideoOpen )
  353.         return DV_ERR_NONSPECIFIC;
  354.  
  355.     CT_Acquire (TRUE);
  356.     CT_IRQClear ();     // Initially clear the interrupt
  357.  
  358.     dwNextFrameNum = 0L;
  359.     dwTimeStart = timeGetTime();
  360.     dwVideoClock = 0;
  361.     dwLastVideoClock = 0;
  362.     gfVideoInStarted = TRUE;
  363.  
  364.     return DV_ERR_OK;
  365. }
  366.  
  367. /*
  368.  *
  369.  * Stop the recording - Finish last buffer if needed 
  370.  * This function implements the DVM_STREAM_STOP message.
  371.  *
  372.  */
  373. WORD FAR PASCAL InStreamStop( void )
  374. {
  375.     if( !fVideoOpen )
  376.         return DV_ERR_NONSPECIFIC;
  377.  
  378.     gfVideoInStarted = FALSE;
  379.     return DV_ERR_OK;
  380. }
  381.  
  382. /*
  383.  *
  384.  * Reset the buffers so that they may be unprepared and freed
  385.  * This function implements the DVM_STREAM_RESET message.
  386.  *
  387.  */
  388. WORD FAR PASCAL InStreamReset( void )
  389. {
  390.     LPVIDEOHDR    lpVHdr;
  391.  
  392.     if( !fVideoOpen )
  393.         return DV_ERR_NONSPECIFIC;
  394.  
  395.     InStreamStop();
  396.  
  397.     while (lpVHdr = DeQueHeader ()) {
  398.  
  399.         lpVHdr->dwFlags |= VHDR_DONE;
  400.  
  401.         videoCallback(MM_DRVM_DATA, (DWORD) lpVHdr);
  402.     }
  403.  
  404.     lpVHdrFirst = NULL;
  405.     lpVHdrLast = NULL;
  406.  
  407.     return DV_ERR_OK;
  408. }
  409.  
  410. /*
  411.  *
  412.  *   ISR
  413.  *       
  414.  *   Actually map the memory over to the next buffer and mark it done
  415.  *      at interrupt time.
  416.  */
  417. void NEAR PASCAL InStreamISR( void )
  418. {
  419.     LPVIDEOHDR  lpVHdr;
  420.     int         j;
  421.     unsigned char huge * hpc;
  422.  
  423.     if (!gfVideoInStarted)
  424.         return;
  425.  
  426. #if FRAME_INTERRUPT
  427.     ;
  428. #else
  429.     if (dwVideoClock & 1L)      // Skip odd fields
  430.         return;
  431. #endif
  432.  
  433.     // make sure enough interrupts have happened since last xfer
  434.     if (dwVideoClock < dwLastVideoClock + 2)
  435.         return;
  436.  
  437.     dwTimeStream = muldiv32 (dwVideoClock, dwMicroSecPerTick, 1000);
  438.  
  439.     // is it time to get the next frame?
  440.     if (dwTimeStream < muldiv32(dwNextFrameNum, dwMicroSecPerFrame, 1000))
  441.         return;
  442.  
  443.     lpVHdr = DeQueHeader();     // get next header.
  444.  
  445.     if (lpVHdr == NULL) {       // No buffers available
  446.     dwFramesSkipped++;
  447.         videoCallback(MM_DRVM_ERROR, dwFramesSkipped); 
  448.         return;
  449.     }
  450.  
  451.     switch (gwDestFormat) {
  452.         case IMAGE_FORMAT_PAL8:
  453.         {
  454.            CT_PrivateAcquire (FALSE);         // Cannot access mem while acquiring
  455.            mapUnpackedYUVto8(lpVHdr->lpData,glpFrameBuffer,fpTrans16to8,
  456.                    gwWidth, gwHeight, gwWidthBytes);
  457.            CT_PrivateAcquire (TRUE);
  458.            dwLastVideoClock = dwVideoClock;
  459.         }   
  460.         break;
  461.  
  462.         case IMAGE_FORMAT_RGB16:
  463.            CT_PrivateAcquire (FALSE);         // Cannot access mem while acquiring
  464.            mapUnpackedYUVtoRGB16(lpVHdr->lpData,glpFrameBuffer, fpYUVtoRGB16,
  465.                    gwWidth, gwHeight, gwWidthBytes);
  466.            CT_PrivateAcquire (TRUE);
  467.            dwLastVideoClock = dwVideoClock;
  468.            break;
  469.  
  470.         case IMAGE_FORMAT_RGB24:
  471.            CT_PrivateAcquire (FALSE);         // Cannot access mem while acquiring
  472.            RectCopyBytes(fpCopyBuffer, gwWidth * 2, 
  473.                glpFrameBuffer, gwWidthBytes,
  474.                0, 0, gwWidth * 2, gwHeight);
  475.            CT_PrivateAcquire (TRUE);
  476.            dwLastVideoClock = dwVideoClock;
  477.            for (j = 0; j < (int) gwHeight; j++) {
  478.                hpc = (unsigned char huge *) fpCopyBuffer + 
  479.                        ((LONG) gwWidth * 2 * j);
  480.                CT_YUV2RGBNoInterp (hpc, (BYTE huge *) lpVHdr->lpData + 
  481.                        ((LONG) gwWidthBytesDest * (gwHeight - (j + 1))), 
  482.                        gwWidth, 24);
  483.            }
  484.            break;
  485.  
  486.         case IMAGE_FORMAT_YUV411UNPACKED:
  487.            CT_PrivateAcquire (FALSE);         // Cannot access mem while acquiring
  488.            RectCopyBytes(lpVHdr->lpData, gwWidth * 2, 
  489.                glpFrameBuffer, gwWidthBytes,
  490.                0, 0, gwWidth * 2, gwHeight);
  491.            CT_PrivateAcquire (TRUE);
  492.            dwLastVideoClock = dwVideoClock;
  493.            break;
  494.  
  495.     }
  496.     
  497.     lpVHdr->dwFlags       |= (VHDR_DONE | VHDR_KEYFRAME);
  498.     lpVHdr->dwBytesUsed    = biDest.biSizeImage;
  499.     lpVHdr->dwTimeCaptured = dwTimeStream;
  500.  
  501.     videoCallback(MM_DRVM_DATA, (DWORD) lpVHdr); // Notify app data is available
  502.  
  503.     dwNextFrameNum++;
  504. }
  505.